/*
 * TimeTaggerConfigure.cpp
 *
 *  Created on: 19.03.2013
 *      Author: mag
 */

#include "stdlib.h"
#include "string.h"
#include "sstream"

#include "TimeTaggerSCPI.h"

#include "../backend/TimeTagger.h"
#include "../backend/Control.h"

#include "../backend/Iterator.h"
#include "../backend/Counter.h"
#include "../backend/Histogram.h"
#include "../backend/Histogram2.h"
#include "../backend/CountBetweenMarkers.h"
#include "../backend/Pulsed.h"
/*
 * :CONFigure
 * 		:HELP?
 * 		:LIST?
 * 		:USE <n>
 * 		:USE?
 * 		:REMOve <n>
 * 		:OVERflow [<n>]
 * 			:HELP?
 * 		:COUNTer [<n>,] <ch1> [,(<binwidth> [,<bins>])]
 * 			:HELP?
 * 		:COUNTRate [<n>,] <ch1> [,(<operational data>)]
 * 			:HELP?
 * 		:HISTOgram [<n>,] <ch1>, [<ch2>] [,(<operational data>)]
 * 			:HELP?
 * 		:CHISTOgram [<n>,] <ch1> [,<ch2>] [,(<operational data>)]
 * 			:HELP?
 * 		:PULSED [<n>,] <chan> [,(<operational data>)]
 * 			:HELP?
 *
 * :CONFigure? [<n>]
 *

 */

static bool parse_new_slot(TimeTaggerSCPIContext *context, int &slot) {
	if (SCPI_ParamInt(context, &slot, false)) {
		if (slot>16) {
			SCPI_ErrorPush(context, ERR_BAD_SLOT_SPEC);
			return false;
		}
	} else {
		slot=Control::find_module_slot();
		if (slot<0) {
			SCPI_ErrorPush(context, ERR_NO_MORE_SLOTS);
			return false;
		}
	}
	if (Control::get_module_slot(slot)) {
		SCPI_ErrorPush(context, ERR_SLOT_IN_USE);
		return false;
	}
	return true;
}

static bool parse_new_slot_and_channel(TimeTaggerSCPIContext *context, int &slot, int &channel) {
	const char *buf;
	size_t len;
	slot=channel=-1;
	if (SCPI_ParamString(context, &buf, &len, true)) {
		if (isdigit(*buf)) {
			slot=atoi(buf);
			if (slot>16) {
				SCPI_ErrorPush(context, ERR_BAD_SLOT_SPEC);
				return false;
			}
			if (!SCPI_ParamString(context, &buf, &len, true))
				return false;
		} else {
			slot=Control::find_module_slot();
			if (slot<0) {
				SCPI_ErrorPush(context, ERR_NO_MORE_SLOTS);
				return false;
			}
		}
		if (Control::get_module_slot(slot)) {
			SCPI_ErrorPush(context, ERR_SLOT_IN_USE);
			return false;
		}

		if (strncmp(buf,"chan",4)!=0) {
			SCPI_ErrorPush(context, ERR_BAD_CHANNEL_SPEC);
			return false;
		}
		char *endp;
		channel=strtol(buf+4, &endp,10);
		if (buf==endp) {
			SCPI_ErrorPush(context, ERR_BAD_CHANNEL_SPEC);
			return false;
		}
		return true;
	}
	return false;
}

static bool parse_2nd_channel(TimeTaggerSCPIContext *context, int &channel) {
	const char *buf;
	size_t len;
	if (SCPI_ParamString(context, &buf, &len, true)) {
		if (strncmp(buf,"chan",4)!=0) {
			SCPI_ErrorPush(context, ERR_BAD_CHANNEL_SPEC);
			return false;
		}
		char *endp;
		channel=strtol(buf+4, &endp,10);
		if (buf==endp) {
			SCPI_ErrorPush(context, ERR_BAD_CHANNEL_SPEC);
			return false;
		}
		return true;
	}
	return false;
}

scpi_result_t TimeTaggerSCPI::CONF_HELP(TimeTaggerSCPIContext *context) {
	std::stringstream ss;
	ss	<< "\r\n:CONFigure? [<n>]"  << "\r\n"
	 	<< ":CONFigure"  << "\r\n"
			<< "\t:HELP?"  << "\r\n"
			<< "\t:LIST?"  << "\r\n"
			<< "\t:USE <n>"  << "\r\n"
			<< "\t:USE?"  << "\r\n"
			<< "\t:REMOve <n>"  << "\r\n"
			<< "\t:OVERflow [<n>]"  << "\r\n"
				<< "\t\t:HELP?"  << "\r\n"
			<< "\t:COUNTer [<n>,] <channel> [,<binwidth> [,<bins>]]"  << "\r\n"
				<< "\t\t:HELP?"  << "\r\n"
			<< "\t:COUNTRate [<n>,] <ch1> [,(<operational data>)]"  << "\r\n"
					<< "\t\t:HELP?"  << "\r\n"
			<< "\t:HISTOgram [<n>,] <ch1>, [<ch2>] [,(<operational data>)]"  << "\r\n"
				<< "\t\t:HELP?"  << "\r\n"
			<< "\t:CHISTOgram [<n>,] <ch1> [,<ch2>] [,(<operational data>)]"  << "\r\n"
				<< "\t\t:HELP?"  << "\r\n"
			<< "\t:PULSED [<n>,] <chan> [,(<operational data>)]"  << "\r\n"
				<< "\t\t:HELP?";

	std::string str = ss.str();
	SCPI_ResultBlock(context, str.c_str(), str.size());

	return SCPI_RES_OK;
}

// :CONFigure::LIST?
scpi_result_t TimeTaggerSCPI::CONF_LIST(TimeTaggerSCPIContext *context) {
	std::stringstream ss;
	size_t numslots;
	_Iterator **slots=Control::get_module_slots(numslots);
	for (size_t n=0; n<numslots; ++n) {
		if (slots[n]!=0) {
			_Iterator *i=slots[n];
			ss << i->getScpiCommand() << ' ' << n;
			std::string p=i->getScpiParameters();
			if (p.size()>0) {
				ss << ',' << p ;
			}
			ss << "\r\n";
		} else {
		}
	}
	ss << "EOT";
	SCPI_ResultString(context, ss.str().c_str());
	return SCPI_RES_OK;
}

scpi_result_t TimeTaggerSCPI::CONF_USE(TimeTaggerSCPIContext *context) {
	int slot;
	if (!SCPI_ParamInt(context,&slot,true))
		return SCPI_RES_ERR;

	context->current_slot=slot;
	return SCPI_RES_OK;
}

scpi_result_t TimeTaggerSCPI::CONF_USE_Q(TimeTaggerSCPIContext *context) {
	SCPI_ResultInt(context, context->current_slot);
	return SCPI_RES_OK;
}


// :CONFigure:OVER:HELP
scpi_result_t TimeTaggerSCPI::CONF_OVER_HELP(TimeTaggerSCPIContext *context) {
	SCPI_ResultString(context,
		"usage: CONFigure:OVERflow [<slot>]"
	);
	return SCPI_RES_OK;
}

// :CONFigure:OVER
scpi_result_t TimeTaggerSCPI::CONF_OVER(TimeTaggerSCPIContext *context) {
	int slot;
	if (!parse_new_slot(context,slot))
		return SCPI_RES_ERR;

	OverFlow *module=new OverFlow();
	Control::set_module_slot(slot, module);

	context->current_slot=slot;

	return SCPI_RES_OK;
}

// :CONFigure::COUNT:HELP?
scpi_result_t TimeTaggerSCPI::CONF_COUNT_HELP(TimeTaggerSCPIContext *context) {
	SCPI_ResultString(context,
		"usage: CONFigure:COUNTer [<slot>] <channel> [,<binwidth> [,<bins]]"
	);
	return SCPI_RES_OK;
}

// :CONFigure:COUNT
scpi_result_t TimeTaggerSCPI::CONF_COUNT(TimeTaggerSCPIContext *context) {
	int slot;
	int channel;
	int binwidth = 1000;
	int bins = 1;

	if (!parse_new_slot_and_channel(context, slot,channel))
		return SCPI_RES_ERR;

	if (SCPI_ParamInt(context,&binwidth,false))
		SCPI_ParamInt(context,&bins,false);

	Counter *module=new Counter(channel, binwidth, bins);
	Control::set_module_slot(slot, module);

	context->current_slot=slot;

	return SCPI_RES_OK;
}


// :CONFigure:COUNTRate:HELP?
scpi_result_t TimeTaggerSCPI::CONF_COUNTR_HELP(TimeTaggerSCPIContext *context) {
	SCPI_ResultString(context,
		"usage: CONFigure:COUNTRate [<slot>,] <channel>"
	);
	return SCPI_RES_OK;
}

// :CONFigure:COUNTRate [<slot>,] <channel>
scpi_result_t TimeTaggerSCPI::CONF_COUNTR(TimeTaggerSCPIContext *context) {
	int slot;
	int channel;

	if (!parse_new_slot_and_channel(context, slot,channel))
		return SCPI_RES_ERR;

	Countrate *module=new Countrate(channel);
	Control::set_module_slot(slot, module);

	context->current_slot=slot;

	return SCPI_RES_OK;
}

// :CONFigure:HISTOgram:HELP?
scpi_result_t TimeTaggerSCPI::CONF_HISTO_HELP(TimeTaggerSCPIContext *context) {
	SCPI_ResultString(context,
		"usage: CONFigure:COUNTRate [<slot>,] <channel>, <channel> [,<binwidth>] "
	);
	return SCPI_RES_OK;
}

// :CONFigure:HISTOgram [<slot>,] <channel1>, <channel2> [,<binwidth>]
scpi_result_t TimeTaggerSCPI::CONF_HISTO(TimeTaggerSCPIContext *context) {
	int slot;
	int channel1,channel2;
	int binwidth=1000;

	if (!parse_new_slot_and_channel(context, slot,channel1))
		return SCPI_RES_ERR;

	if (!parse_2nd_channel(context, channel2))
		return SCPI_RES_ERR;

	SCPI_ParamInt(context,&binwidth,false);

	Histogram *module=new Histogram(channel1, channel2, binwidth);
	Control::set_module_slot(slot, module);

	context->current_slot=slot;

	return SCPI_RES_OK;
}

// :CONFigure:DISTribution:HELP?
scpi_result_t TimeTaggerSCPI::CONF_DIST_HELP(TimeTaggerSCPIContext *context) {
	SCPI_ResultString(context,
		"usage: CONFigure:DISTribution [<slot>,] <channel> [,<divisor>] "
	);
	return SCPI_RES_OK;
}

// :CONFigure:DISTribution [<slot>,] <channel1>, <channel2>,<divisor>
scpi_result_t TimeTaggerSCPI::CONF_DIST(TimeTaggerSCPIContext *context) {
	int slot;
	int channel;
	int divisor=1;

	if (!parse_new_slot_and_channel(context, slot,channel))
		return SCPI_RES_ERR;

	if (!SCPI_ParamInt(context,&divisor,true))
		return SCPI_RES_ERR;

	Distribution *module=new Distribution(channel, divisor);
	Control::set_module_slot(slot, module);

	context->current_slot=slot;

	return SCPI_RES_OK;
}

// :CONFigure:CHISTOgram:HELP?
scpi_result_t TimeTaggerSCPI::CONF_CHISTO_HELP(TimeTaggerSCPIContext *context) {
	SCPI_ResultString(context,
		"usage: CONFigure:CHISTOgram [<slot>,] <channel> [,<binwidth> [,<timespan]] "
	);
	return SCPI_RES_OK;
}

// :CONFigure:CHISTOgram [<slot>,] <channel1>, <channel2>,<divisor>
scpi_result_t TimeTaggerSCPI::CONF_CHISTO(TimeTaggerSCPIContext *context) {
	int slot;
	int channel1,channel2;
	int binwidth=4096;
	int timespan=4096;

	if (!parse_new_slot_and_channel(context, slot,channel1))
		return SCPI_RES_ERR;
	if (!parse_2nd_channel(context, channel2))
		return SCPI_RES_ERR;

	if (!SCPI_ParamInt(context,&binwidth,false)) {
		SCPI_ParamInt(context,&timespan,false);
	}

	Histogram2 *module=new Histogram2(channel1,channel2, binwidth, timespan);
	Control::set_module_slot(slot, module);

	context->current_slot=slot;

	return SCPI_RES_OK;
}

// :CONFigure:COUNTBetweenmarkers:HELP?
scpi_result_t TimeTaggerSCPI::CONF_COUNTB_HELP(TimeTaggerSCPIContext *context) {
	SCPI_ResultString(context,
		"usage: CONFigure:COUNTBetweenmarkers [<slot>,] <channel1>, <channel2> [,<binwidth>] "
	);
	return SCPI_RES_OK;
}

// :CONFigure:COUNTBetweenmarkers [<slot>,] <channel1>, <channel2>,<divisor>
scpi_result_t TimeTaggerSCPI::CONF_COUNTB(TimeTaggerSCPIContext *context) {
	int slot;
	int channel1,channel2;
	int binwidth=4096;

	if (!parse_new_slot_and_channel(context, slot,channel1))
		return SCPI_RES_ERR;
	if (!parse_2nd_channel(context, channel2))
		return SCPI_RES_ERR;

	if (!SCPI_ParamInt(context,&binwidth,true))
		return SCPI_RES_ERR;;

	CountBetweenMarkers *module=new CountBetweenMarkers(channel1,channel2, binwidth);
	Control::set_module_slot(slot, module);

	context->current_slot=slot;

	return SCPI_RES_OK;
}

// :CONFigure:PULSED:HELP?
scpi_result_t TimeTaggerSCPI::CONF_PULSED_HELP(TimeTaggerSCPIContext *context) {
	SCPI_ResultString(context,
			"usage: CONFigure:COUNTBetweenmarkers [<slot>,] <channel1>, <channel2>, <channel3>, <length>, <binwidth>, <sequence_length>"
	);
	return SCPI_RES_OK;
}

// CONFigure:COUNTBetweenmarkers [<slot>,] <channel1>, <channel2>, <channel3>, <length>, <binwidth>, <sequence_length>"
scpi_result_t TimeTaggerSCPI::CONF_PULSED(TimeTaggerSCPIContext *context) {
	int slot;
	int channel1,channel2, channel3;
	int length;
	int binwidth;
	int sequence_length;

	if (!parse_new_slot_and_channel(context, slot,channel1))
		return SCPI_RES_ERR;
	if (!parse_2nd_channel(context, channel2))
		return SCPI_RES_ERR;
	if (!parse_2nd_channel(context, channel3))
		return SCPI_RES_ERR;

	if (!SCPI_ParamInt(context,&length,true))
		return SCPI_RES_ERR;
	if (!SCPI_ParamInt(context,&binwidth,true))
		return SCPI_RES_ERR;
	if (!SCPI_ParamInt(context,&sequence_length,true))
		return SCPI_RES_ERR;

	Pulsed *module=new Pulsed(length, binwidth, sequence_length, channel1,channel2, channel3);
	Control::set_module_slot(slot, module);

	context->current_slot=slot;

	return SCPI_RES_OK;
}
